//
// Created by martin on 2/16/22.
//

#ifndef MUDUO_BUFFER_H
#define MUDUO_BUFFER_H

#include "muduo/base/copyable.h"
#include "muduo/base/Types.h"
#include "muduo/base/StringPiece.h"
//#include "muduo/net/SocketsOps.h"
#include "muduo/net/Endian.h"

#include <vector>
#include <algorithm>
#include <assert.h>
//#include <unistd.h> // ssize_t


namespace muduo
{
namespace net
{

/**
 * A buffer class modeled after org.jboss.netty.buffer.ChannelBuffer
 *
 * @code
 * +-----------------------------------------------------------+
 * | prependable bytes |  readable bytes   |  writable bytes   |
 * |                   |                   |                   |
 * +-----------------------------------------------------------+
 * |                   |                   |                   |
 * 0       <=     readerIndex    <=    writerIndex     <=     fileSize
 * @endcode
 */
class Buffer : public muduo::copyable
{
public:
    static const size_t kCheapPrepend = 8;   // 初始预留的prependable空间大小
    static const size_t kInitialSize = 1024; // Buffer初始大小

    /* 构造函数 内部缓冲区buffer_初始大小默认kCheapPrepend + initialSize (1032byte) */
    explicit Buffer(size_t initialSize = kInitialSize)
    : buffer_(kCheapPrepend + initialSize),
      readerIndex_(kCheapPrepend), // 8
      writerIndex_(kCheapPrepend)  // 8
    {
        assert(readableBytes() == 0);
        assert(writableBytes() == initialSize);
        assert(prependableBytes() == kCheapPrepend);
    }

    /*
     * implicit copy-ctor, move-ctor, dtor and assignment are fine
     * NOTE: implicit move-ctor is added in g++ 4.6
     */

    /* 与rhs交换当前缓冲区 */
    void swap(Buffer& rhs)
    {
        buffer_.swap(rhs.buffer_);
        std::swap(readerIndex_, rhs.readerIndex_);
        std::swap(writerIndex_, rhs.writerIndex_);
    }

    /* 返回 readable 空间大小 */
    size_t readableBytes() const
    { return writerIndex_ - readerIndex_; }

    /* 返回 writeable 空间大小 */
    size_t writableBytes() const
    { return buffer_.size() - writerIndex_; }

    /* 返回 prependable 空间大小 */
    size_t prependableBytes() const
    { return readerIndex_; }

    /* readIndex 对应元素地址 */
    const char* peek() const
    { return begin() + readerIndex_; }

    /* 在readable空间找CRLF位置, 返回第一个出现CRLF的位置 */
    // CR = '\r', LF = '\n'
    const char* findCRLF() const
    {
        // FIXME: replace with memmem()?
        const char* crlf = std::search(peek(), beginWrite(), kCRLF, kCRLF+2);
        return crlf == beginWrite() ? NULL : crlf;
    }

    /* 在start~writable首地址 之间找CRLF, 要求start在readable地址空间中 */
    // CR = '\r', LF = '\n'
    const char* findCRLF(const char* start) const
    {
        assert(peek() <= start);
        assert(start <= beginWrite());
        // FIXME: replace with memmem()?
        const char* crlf = std::search(start, beginWrite(), kCRLF, kCRLF+2);
        return crlf == beginWrite() ? NULL : crlf;
    }

    /* 在readable空间中找EOL, 即LF('\n') */
    // EOL = '\n'
    // find end of line ('\n') from range [peek(), end)
    const char* findEOL() const
    {
        const void* eol = memchr(peek(), '\n', readableBytes());
        return static_cast<const char*>(eol);
    }

    /* 在start~writable首地址 之间找EOL, 要求start在readable地址空间中 */
    // EOL = '\n
    // find end of line ('\n') from range [start(), end)
    // @require peek() < start
    const char* findEOL(const char* start) const
    {
        assert(peek() <= start);
        assert(start <= beginWrite());
        const void* eol = memchr(start, '\n', beginWrite() - start);
        return static_cast<const char*>(eol);
    }

    /* 从readable头部取走最多长度为len byte的数据. 会导致readable空间变化, 可能导致writable空间变化.
     * 这里取走只是移动readerIndex_, writerIndex_, 并不会直接读取或清除readable, writable空间数据　*/
    /*
     * retrieve() returns void, to prevent
     * string str(retrieve(readableBytes()), readableBytes());
     * the evaluation of two functions are unspecified
     */
    void retrieve(size_t len)
    {
        assert(len <= readableBytes());
        if (len < readableBytes()) // readable 中数据充足时, 只取走len byte数据
        {
            readerIndex_ += len;
        }
        else
        { // readable中数据不足时, 取走所有数据
            retrieveAll();
        }
    }
    /* 从readable空间取走 [peek(), end)这段区间数据, peek()是readable空间首地址 */
    void retrieveUntil(const char* end)
    {
        assert(peek() <= end);
        assert(end <= beginWrite());
        retrieve(end - peek());
    }
    /* 从readable空间取走一个int64_t数据, 长度8byte */
    void retrieveInt64()
    {
        retrieve(sizeof(int64_t));
    }
    /* 从readable空间取走一个int32_t数据, 长度4byte */
    void retrieveInt32()
    {
        retrieve(sizeof(int32_t));
    }
    /* 从readable空间取走一个int16_t数据, 长度2byte */
    void retrieveInt16()
    {
        retrieve(sizeof(int16_t));
    }
    /* 从readable空间取走一个int8_t数据, 长度1byte */
    void retrieveInt8()
    {
        retrieve(sizeof(int8_t));
    }
    /* 从readable空间取走所有数据, 直接移动readerIndex_, writerIndex_指示器即可 */
    void retrieveAll()
    {
        readerIndex_ = kCheapPrepend;
        writerIndex_ = kCheapPrepend;
    }
    /* 从readable空间取走所有数据, 转换为字符串返回 */
    std::string retrieveAllAsString()
    {
        return retrieveAsString(readableBytes());
    }
    /* 从readable空间头部取走长度len byte的数据, 转换为字符串返回 */
    std::string retrieveAsString(size_t len)
    {
        assert(len <= readableBytes());
        string result(peek(), len);
        retrieve(len);
        return result;
    }
    /* 从readable空间读取所有数据, 转换为StringPiece返回 */
    StringPiece toStringPiece() const
    {
        return StringPiece(peek(), static_cast<int>(readableBytes()));
    }

    /* 将字符串str添加到缓冲区末尾, 即writable空间起始位置 */
    void append(const StringPiece& str)
    {
        append(str.data(), str.size());
    }

    /* 将字符数组data[len]添加到缓冲区末尾 */
    void append(const char* data, size_t len)
    {
        ensureWritableBytes(len);
        std::copy(data, data + len, beginWrite());
        hasWritten(len);
    }

    /* 将二进制数据data[len]添加到缓冲区末尾 */
    void append(const void* data, size_t len)
    {
        append(static_cast<const char*>(data), len);
    }

    /* 确保缓冲区writable空间大小 >= len byte */
    void ensureWritableBytes(size_t len)
    {
        if (writableBytes() < len)
        {
            makeSpace(len);
        }
        assert(writableBytes() >= len);
    }
    /* 返回待写入数据的地址, 即writable空间首地址 */
    char* beginWrite()
    { return begin() + writerIndex_; }
    const char* beginWrite() const
    { return begin() + writerIndex_; }

    /* 将writerIndex_往后移动len byte, 需要确保writable空间足够大 */
    void hasWritten(size_t len)
    {
        assert(len <= writableBytes());
        writerIndex_ += len;
    }
    /* 将writerIndex_往前移动len byte, 需要确保readable空间足够大 */
    /*
     * Cancel written bytes.
     */
    void unwrite(size_t len)
    {
        assert(len <= readableBytes());
        writerIndex_ -= len;
    }

    /* 写一个int64_t类型数x到缓冲区末尾, 即readable空间末尾 */
    /**
     * Append int64_t using network endian
     */
    void appendInt64(int64_t x)
    {
        int64_t be64 = sockets::hostToNetwork64(x); // 将x转换为网络字节序(大端)
        append(&be64, sizeof(be64));
    }
    /* 写一个int32_t类型数x到缓冲区末尾, 即readable空间末尾 */
    /**
     * Append int32_t using network endian
     */
    void appendInt32(int32_t x)
    {
        int32_t be32 = static_cast<int32_t>(sockets::hostToNetwork32(x));
        append(&be32, sizeof(be32));
    }
    /* 写一个int16_t类型数x到缓冲区末尾, 即readable空间末尾 */
    /**
     * Append int16_t using network endian
     */
    void appendInt16(int16_t x)
    {
        int16_t be16 = static_cast<int16_t>(sockets::hostToNetwork16(x));
        append(&be16, sizeof(be16));
    }
    /* 写一个int8_t类型数x到缓冲区末尾, 即readable空间末尾 */
    /**
     * Append int8_t using network endian
     */
    void appendInt8(int8_t x)
    {
        append(&x, sizeof(x));
    }

    /* 从readable空间头部读取一个int64_类型数, 由网络字节序转换为本地字节序 */
    /**
     * Read int64_t from network endian
     *
     * Require: buf->readableBytes() >= sizeof(int64_t)
     */
    int64_t readInt64()
    {
        int64_t result = peekInt64();
        retrieveInt64();
        return result;
    }
    /* 从readable空间头部读取一个int32_类型数, 由网络字节序转换为本地字节序 */
    int32_t readInt32()
    {
        int32_t result = peekInt32();
        retrieveInt32();
        return result;
    }
    /* 从readable空间头部读取一个int16_类型数, 由网络字节序转换为本地字节序 */
    int16_t readInt16()
    {
        int16_t result = peekInt16();
        retrieveInt16();
        return result;
    }
    /* 从readable空间头部读取一个int8_类型数, 由网络字节序转换为本地字节序 */
    int8_t readInt8()
    {
        int8_t result = peekInt8();
        retrieveInt8();
        return result;
    }

    /* 从readable的头部peek()读取一个int64_t数据, 但不移动readerIndex_, 不会改变readable空间 */
    /**
     * Peek int64_t from network endian
     *
     * Require: buf->readableBytes() >= sizeof(int64_t)
     */
    int64_t peekInt64() const
    {
        assert(readableBytes() >= sizeof(int64_t));
        int64_t be64 = 0;
        ::memcpy(&be64, peek(), sizeof(be64));
        return sockets::networkToHost64(be64); // 网络字节序转换为本地字节序
    }
    /* 从readable的头部peek()读取一个int32_t数据, 但不移动readerIndex_, 不会改变readable空间 */
    int32_t peekInt32() const
    {
        assert(readableBytes() >= sizeof(int32_t));
        int32_t be32 = 0;
        ::memcpy(&be32, peek(), sizeof(be32));
        return sockets::networkToHost32(be32); // 网络字节序转换为本地字节序
    }
    /* 从readable的头部peek()读取一个int16_t数据, 但不移动readerIndex_, 不会改变readable空间 */
    int16_t peekInt16() const
    {
        assert(readableBytes() >= sizeof(int16_t));
        int16_t be16 = 0;
        ::memcpy(&be16, peek(), sizeof(be16));
        return sockets::networkToHost16(be16); // 网络字节序转换为本地字节序
    }
    /* 从readable的头部peek()读取一个int8_t数据, 但不移动readerIndex_, 不会改变readable空间.
     * 1byte数据不存在字节序问题 */
    int8_t peekInt8() const
    {
        assert(readableBytes() >= sizeof(int8_t));
        int8_t x = *peek();
        return x;
    }
    /* 在prependable空间末尾预置int64_t类型网络字节序的数x, 预置数会被转化为本地字节序 */
    /**
     * Prepend int64_t using network endian
     */
     void prependInt64(int64_t x)
    {
         int64_t be64 = sockets::hostToNetwork64(x);
         prepend(&be64, sizeof(be64));
    }
    /* 在prependable空间末尾预置int32_t类型网络字节序的数x, 预置数会被转化为本地字节序 */
    /**
     * Prepend int32_t using network endian
     */
    void prependInt32(int32_t x)
    {
        int64_t be32 = sockets::hostToNetwork32(x);
        prepend(&be32, sizeof(be32));
    }
    /* 在prependable空间末尾预置int16_t类型网络字节序的数x, 预置数会被转化为本地字节序 */
    void prependInt16(int16_t x)
    {
        int16_t be16 = sockets::hostToNetwork16(x);
        prepend(&be16, sizeof(be16));
    }
    /* 在prependable空间末尾预置int8_t类型网络字节序的数x, 预置数会被转化为本地字节序 */
    void prependInt8(int8_t x)
    {
        prepend(&x, sizeof(x));
    }
    /* 在prependable空间末尾预置一组二进制数据data[len].
     * 表面上看是加入prependable空间末尾, 实际上是加入readable开头,　会导致readerIndex_变化 */
    void prepend(const void* data, size_t len)
    {
        assert(len <= prependableBytes());
        readerIndex_ -= len;
        const char* d = static_cast<const char*>(data);
        std::copy(d, d+len, begin()+readerIndex_);
    }

    /* 收缩缓冲区空间, 将缓冲区中数据拷贝到新缓冲区, 确保writable空间最终大小为reserve */
    void shrink(size_t reserve)
    {
        // FIXME: use vector::shrink_to_fit() in C++ 11 if possible.
        Buffer other;
        other.ensureWritableBytes(readableBytes() + reserve);
        other.append(toStringPiece());
        swap(other);
    }

    /* 返回buffer_的容量capacity() */
    size_t internalCapacity() const
    {
        return buffer_.capacity();
    }

    /* 从指定fd读取数据, 存放到当前缓冲区writable空间. savedErrno保存读取过程出现的系统调用错误
     * 返回读取的字节数. >=0 代表读取成功; < 0, 代表读取出现错误; */
    /**
     * Read data directly into buffer.
     *
     * It may implement with readv(2)
     * @param fd file descriptor
     * @param savedErrno [out] saved errno result from this function
     * @return result of read(2), @c errno is saved
     */
    ssize_t readFd(int fd, int* savedErrno);

private:
    /* 返回缓冲区的起始位置, 也是prependable空间起始位置 */
    char* begin()
    {
//       <=> return buffer_.data();
        return &*buffer_.begin();
    }
    const char* begin() const
    { return &*buffer_.begin(); }

    /* writable空间不足以写入len byte数据时,
     * 1)如果writable空间 + prependable空间不足以存放数据, 就resize 申请新的更大的内部缓冲区buffer_
     * 2)如果足以存放数据, 就将prependable多余空间腾挪出来, 合并到writable空间 */
    void makeSpace(size_t len)
    {
        if (writableBytes() + prependableBytes() < len + kCheapPrepend)
        { // writable 空间大小 + prependable空间大小 不足以存放len byte数据, resize内部缓冲区大小
            // FIXME: move readable data
            buffer_.resize(writerIndex_ + len);
        }
        else
        { // writable 空间大小 + prependable空间大小 足以存放len byte数据, 移动readable空间数据, 合并多余prependable空间到writable空间
            // TODO: ???
            // move readable data to the front, make space inside buffer
            assert(kCheapPrepend < readerIndex_);
            size_t readable = readableBytes();
            std::copy(begin() + readerIndex_,
                      begin() + writerIndex_,
                      begin() + kCheapPrepend);
            readerIndex_ = kCheapPrepend;
            writerIndex_ = readerIndex_ + readable;
            assert(readable == readableBytes());
        }
    }

    std::vector<char> buffer_; // 存储数据的线性缓冲区, 大小可变
    size_t readerIndex_; // 可读数据首地址, i.e. readable空间首地址
    size_t writerIndex_; // 可写数据首地址, i.e. writable空间首地址

    static const char kCRLF[]; // CRLF, 定义为"\r\n"
};

} // namespace net
} // namespace muduo


#endif //MUDUO_BUFFER_H
